package program

import (
	"io/ioutil"
	"mi/compiler/ast"
	"mi/compiler/host"
	"mi/compiler/parser"
	"mi/compiler/performance"
	"mi/internal/system"
	"mi/internal/xpath"
	"os"
	"path"
	"path/filepath"
)

type compilerHost struct {}

func CreateCompilerHost() host.CompilerHost {
	return new(compilerHost)
}

func (c *compilerHost) GetProjectFile(uri  xpath.URI, onError func(message string)) *ast.ProjectFile {
	performance.Mark("beforeIORead")
	data, err := ioutil.ReadFile(uri.Filename())
	performance.Mark("afterIORead")
	performance.Measure("I/O Read", "beforeIORead", "afterIORead")
	if err != nil {
		if onError != nil {
			onError(err.Error())
		}
	}
	return parser.ParseProjectFile(uri, data)
}

func (c *compilerHost) GetPackage(uri xpath.URI, project *ast.ProjectFile) *ast.Package {
	var pkg = new(ast.Package)
	pkg.PackageName = filepath.Base(uri.Filename())
	pkg.Version = project.Version
	pkg.ProjectFile = project
	pkg.DiskPath = uri
	pkg.Files = make(map[string]*ast.SourceFile)
	pkg.Status = ast.PreLoad
	return pkg
}

func (c *compilerHost) GetSourceFile(uri  xpath.URI, languageVersion ast.ScriptTarget, onError func(message string)) *ast.SourceFile {
	performance.Mark("beforeIORead")
	data, err := ioutil.ReadFile(uri.Filename())
	performance.Mark("afterIORead")
	performance.Measure("I/O Read", "beforeIORead", "afterIORead")
	if err != nil {
		if onError != nil {
			onError(err.Error())
		}
	}
	return parser.ParseSourceFile(uri, data, ast.Java8, ast.MI)
}

func (c *compilerHost) WriteFile(uri xpath.URI, data []byte, onError func(message string)) {
	err := os.MkdirAll(path.Dir(uri.Filename()), os.ModePerm)
	if err != nil {
		if onError != nil {
			onError(err.Error())
		}
		return
	}
	performance.Mark("beforeIOWrite")
	err = ioutil.WriteFile(uri.Filename(), data, os.ModePerm)
	performance.Mark("afterIOWrite")
	performance.Measure("I/O Read", "beforeIOWrite", "afterIOWrite")
	if err != nil {
		if onError != nil {
			onError(err.Error())
		}
		return
	}
}

func (c *compilerHost) GetCurrentDirectory() string {
	return system.CurrentDirectory()
}

func (c *compilerHost) UseCaseSensitiveFileNames() bool {
	return system.UseCaseSensitiveFileNames()
}

func (c *compilerHost) GetNewLine() string {
	return system.NewLine()
}

